package jalgebrava.group.groups;


import static jalgebrava.util.collections.IterableMixins.*;
import jalgebrava.group.Group;
import jalgebrava.group.GroupElement;
import jalgebrava.util.F;
import jalgebrava.util.collections.ImmutableIterable;
import jalgebrava.util.collections.ImmutableIterator;

import java.util.HashMap;
import java.util.Map;


public class AccountingGroup<G> extends Group<G> {
	private final Group<G> group;
	private final Map<String, Integer> methodCounts = new HashMap<String, Integer>();
	public AccountingGroup(Group<G> inGroup) {
		super("Accounting(" + inGroup.getDescription() + ")");
		this.group = inGroup;
	}
	
	private final void increaseCount(String methodName) {
		Integer count = methodCounts.get(methodName);
		if (count == null) {
			methodCounts.put(methodName, 1); 
			return;
		}
		methodCounts.put(methodName, count + 1);		
	}
	@Override
	public final boolean contains(G x) {
		increaseCount("contains(G)");
		return group.contains(x);
	}
	@Override
	public final ImmutableIterable<GroupElement<G>> elements() {
		F<GroupElement<G>, GroupElement<G>> adopt = new F<GroupElement<G>, GroupElement<G>>() {

			@Override
			public GroupElement<G> apply(GroupElement<G> a) {
				return elementAssert(a.g);
			}
			
		};
		increaseCount("elements()");
		return map(group.elements(), adopt);
	}
	public final boolean equals(G x, G y) {
		increaseCount("equals(G,G)");
		return group.equals(x, y);
	}
	@Override
	public final boolean equals(Object obj) {
		increaseCount("equals(Object");
		return group.equals(obj);
	}
	@Override
	public final int hashCode() {
		increaseCount("hashCode()");
		return group.hashCode();
	}
	public final int hashCode(G x) {
		increaseCount("hashCode(G)");
		return group.hashCode(x);
	}
	@Override
	public final G inv(G x) {
		increaseCount("inv(G)");
		return group.inv(x);
	}
	@Override
	public final G mul(G x, G y) {
		increaseCount("mul(G,G)");
		return group.mul(x, y);
	}
	@Override
	public final ImmutableIterator<G> iterator() {
		increaseCount("iterator()");
		return group.iterator();
	}
	public final int size() {
		increaseCount("size()");
		return group.size();
	}
	@Override
	public final String toShortString(G g) {
		increaseCount("toShortString(G)");
		return group.toShortString(g);
	}
	@Override
	public final String toString() {
		increaseCount("toString()");
		return group.toString();
	}
	public final String toString(G x) {
		increaseCount("toString(G)");
		return group.toString(x);
	}
	@Override
	public final G unit() {
		increaseCount("unit");
		return group.unit();
	}

	public final void dumpMethodCounts() {
		System.out.println("-------------------");
		System.out.println("Dumping method counts for " + group.getDescription());
		for (Map.Entry<String,Integer> entry: methodCounts.entrySet()) {
			System.out.println(entry);
		}
		System.out.println("-------------------");
		methodCounts.clear();
	}

}
